package com.glsc.ngateway.ldap.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.glsc.ngateway.common.api.common.enums.Constant;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrDeptDto;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrDeptSearchDto;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrEmpDto;
import com.glsc.ngateway.common.api.platform.dto.system.SystemConfigDto;
import com.glsc.ngateway.common.api.platform.feign.IFeignPlatformService;
import com.glsc.ngateway.common.api.platform.resp.PlatformResponse;
import com.glsc.ngateway.common.base.converter.ldap.LdapEhrDeptConverter;
import com.glsc.ngateway.common.base.domain.mysql.gateway.ldap.DepartmentVisitSystem;
import com.glsc.ngateway.common.base.domain.mysql.gateway.ldap.LdapEhrDept;
import com.glsc.ngateway.common.base.domain.mysql.gateway.ldap.UserVisitSystem;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.User;
import com.glsc.ngateway.common.base.repo.mysql.gateway.ldap.LdapDepartmentSystemRepo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.ldap.LdapEhrDeptRepo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.ldap.LdapUserSystemRepo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.MysqlUserRepository;
import com.glsc.ngateway.common.base.service.MailServiceCommon;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class LdapEhrDeptService {

    Logger logger = LoggerFactory.getLogger(LdapEhrDeptService.class);

    @Resource
    private LdapEhrEmpService ldapEhrEmpService;

    @Resource
    private LdapEhrDeptRepo ldapEhrDeptRepo;

    @Resource
    private MysqlUserRepository mysqlUserRepository;

    @Resource
    private LdapDepartmentSystemRepo deptSystemVisRepo;

    @Resource
    private LdapUserSystemRepo ldapUserSystemRepo;

    @Resource
    private IFeignPlatformService iFeignPlatformService;

    @Resource
    private MailServiceCommon mailServiceCommon;

    private static final String LEVLE_1_DEPT = "一级部门";
    private static final String LEVLE_2_DEPT = "二级部门";

    public List<LdapEhrDeptDto> findAll() {
        return LdapEhrDeptConverter.domain2Dto(ldapEhrDeptRepo.findAll());
    }

    public List<LdapEhrDept> findAllByOaDeptIds(List<Integer> oaIds) {
        return ldapEhrDeptRepo.findAllByOaDeptIdIn(oaIds);
    }

    public LdapEhrDeptDto findByBadge(@NotBlank String account) throws Exception {
        LdapEhrEmpDto ehr = Optional.ofNullable(ldapEhrEmpService.findByBadge(account)).orElseThrow(() -> new Exception("ehr未找到用户:" + account));
        return ldapEhrDeptRepo.findById(ehr.getDepid()).map(LdapEhrDeptConverter::domain2Dto).orElseThrow(() -> new Exception(String.format("ehr未找到部门: %s, %s", ehr.getDepid(), ehr.getTitle())));
    }

    /**
     * 根据domain进行simple查找，不包含任何关联业务逻辑
     * @param deptDto
     * @return
     */
    public List<LdapEhrDeptDto> findDeptByCondition(LdapEhrDeptDto deptDto){
        List<LdapEhrDept> deptList = ldapEhrDeptRepo.findAll(Example.of(LdapEhrDeptConverter.dto2Domain(deptDto)));
        if (CollectionUtil.isEmpty(deptList)) {
            return null;
        }
        List<LdapEhrDeptDto> resList = Lists.newArrayList();
        for (LdapEhrDept ldapEhrDept : deptList) {
            resList.add(LdapEhrDeptConverter.domain2Dto(ldapEhrDept));
        }
        return resList;
    }

    public List<LdapEhrDeptDto> findAll(LdapEhrDeptSearchDto param) throws Exception {
        List<LdapEhrDeptDto> allDepts = LdapEhrDeptConverter.domain2Dto(ldapEhrDeptRepo.query(param));
        if (Strings.isNotBlank(param.getCompTitleOrDepId())) {
            switch (param.getCompTitleOrDepId()) {
                case Constant.BRANCH_ORGANIZATION:
                    allDepts = allDepts.stream()
                            .filter(d -> d.getComptitle().endsWith("分公司") || d.getDtitle().endsWith("营业部"))
                            .collect(Collectors.toList());
                    break;
                case Constant.SUB_COMPANY:
                    PlatformResponse<SystemConfigDto> configResp = iFeignPlatformService.findConfigByCode(Constant.CONFIG_KEY_SUB_COMPANY_LIST);
                    if (Objects.isNull(configResp) || Objects.isNull(configResp.getData())) {
                        throw new Exception("未找到配置项:" + Constant.CONFIG_KEY_SUB_COMPANY_LIST);
                    }
                    Set<String> subCompanySet = Arrays.stream(configResp.getData().getConfigValue().split(",")).collect(Collectors.toSet());
                    allDepts = allDepts.stream()
                            .filter(d -> subCompanySet.contains(d.getComptitle()))
                            .collect(Collectors.toList());
                    break;
//                case Constant.HEAD_QUARTERS:
//                    allDepts = allDepts.stream()
//                            .filter(d -> d.getComptitle().equals(Constant.HEAD_QUARTERS))
//                            .collect(Collectors.toList());
//                    break;
                default:
                    //如果包含中文，直接进行通过公司筛选
                    if(containsChinese(param.getCompTitleOrDepId())){
                        allDepts = allDepts.stream()
                                .filter(d -> d.getComptitle().equals(param.getCompTitleOrDepId()))
                                .collect(Collectors.toList());
                        break;
                    }
                    //选择的是部门
                    Map<Integer, List<LdapEhrDeptDto>> parentDepMap = allDepts.stream()
                            .filter(d -> Objects.nonNull(d.getSuperDeptId()))
                            .collect(Collectors.groupingBy(LdapEhrDeptDto::getSuperDeptId));
                    List<LdapEhrDeptDto> allQueryDepIds = new ArrayList<>();
                    //bfs遍历选择部门下所有部门id
                    Queue<LdapEhrDeptDto> que = new LinkedList<>();
                    Optional<LdapEhrDeptDto> root = ldapEhrDeptRepo.findById(Integer.valueOf(param.getCompTitleOrDepId())).map(LdapEhrDeptConverter::domain2Dto);
                    que.add(root.orElseThrow());
                    while (!que.isEmpty()) {
                        LdapEhrDeptDto depId = que.poll();
                        allQueryDepIds.add(depId);
                        if (parentDepMap.containsKey(depId.getDepid())) {
                            que.addAll(parentDepMap.get(depId.getDepid()));
                        }
                    }
                    allDepts = allQueryDepIds;
            }
        }
        return allDepts;
    }

    public String getUserDepartment(String userName, Boolean isPlatformUser) {
        //暂时自有用户直接取部门，因为有一些特定部门无法同步至ldap_dept表中，无法通过其获取上级部门
        if (isPlatformUser) {
            User user = mysqlUserRepository.findByUsername(userName);
            //只要一级部门
            return StringUtils.isNotBlank(user.getUserDepartment()) ? user.getUserDepartment().split("/")[0] : StringUtils.EMPTY;
        } else {
            LdapEhrEmpDto ehr = ldapEhrEmpService.findByBadge(userName);
            if (Objects.isNull(ehr)) {
                logger.error("未找到用户信息{}", userName);
                return Strings.EMPTY;
            }
            if (Objects.isNull(ehr.getDepid())) {
                logger.error("未找到用户部门{}", ehr.getDepid());
                return Strings.EMPTY;
            }
            LdapEhrDept dept = ldapEhrDeptRepo.getById(ehr.getDepid());
            if (LEVLE_1_DEPT.equals(dept.getDepgrade())) {
                return dept.getDtitle();
            } else if (LEVLE_2_DEPT.equals(dept.getDepgrade())) {
                return Strings.isNotBlank(dept.getAtitle()) ? dept.getAtitle(): dept.getDtitle();
            } else {
                //更低级部门，循环向上找，直到一级部门
                Optional<LdapEhrDept> parentDept = ldapEhrDeptRepo.findById(dept.getSuperDeptId());
                while (parentDept.isPresent() && !LEVLE_1_DEPT.equals(parentDept.get().getDepgrade())) {
                    parentDept = ldapEhrDeptRepo.findById(parentDept.get().getSuperDeptId());
                }
                //未找到用自己的
                String sspDept = parentDept.isPresent() ? parentDept.get().getDtitle() : dept.getDtitle();
                logger.info("匹配二级以下部门信息{}, 最上级部门{}", dept.getDtitle(), sspDept);
                return sspDept;
            }
        }
    }

    public String getSystemIdByDepartment(String department, String companyName) {
        List<DepartmentVisitSystem> departmentVisitSystem = deptSystemVisRepo.findAllByDepartment(department);
        if (departmentVisitSystem == null) {
            return null;
        } else {
            if (departmentVisitSystem.size() == 1){
                if (!StrUtil.equals(departmentVisitSystem.get(0).getComptitle(),companyName)){
                    mailServiceCommon.sendMailToAdmin("网关ldap错误", department+"部门，"+companyName+"公司名未匹配");
                }
                return departmentVisitSystem.get(0).getSystemId();
            } else {
                List<DepartmentVisitSystem> companyResult = deptSystemVisRepo.findAllByDepartmentAndComptitle(department,companyName);
                if (CollectionUtil.isEmpty(companyResult)){
                    if (departmentVisitSystem.size() > 1){
                        mailServiceCommon.sendMailToAdmin("网关ldap错误", department+"部门，"+"无公司名匹配重复配置访问权限");
                        return departmentVisitSystem.get(0).getSystemId();
                    }
                    return null;
                } else if (companyResult.size() != 1 ){
                    mailServiceCommon.sendMailToAdmin("网关ldap错误", department+"部门，"+companyName+"重复配置访问权限");
                }
                return companyResult.get(0).getSystemId();
            }
        }
    }
    public boolean containsChinese(String str) {
        String regex = "[\u4e00-\u9fa5]";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(str);
        return matcher.find();
    }

    public String getSystemIdByUser(String account) {
        UserVisitSystem userVisitSystem = ldapUserSystemRepo.findOneByUserAccount(account);
        if (Objects.nonNull(userVisitSystem) ){
            return userVisitSystem.getSystemId();
        }
        return "";
    }
}
